package com.flyqiu.common.sc;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.flyqiu.common.clazz.FlyQiuClassTools;
import com.flyqiu.common.sc.calculate.*;
import com.flyqiu.common.sc.statistical.FlyQiuPropertyStatistical;
import com.flyqiu.common.single.FlyQiuSingletonFactory;
import com.flyqiu.common.single.FlyQiyBaseSingleton;
import com.flyqiu.common.tools.FlyQiuCollectionTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 统计计算管理类。
 * 负责管理和创建不同的统计计算实例。
 */
@Slf4j
public class FlyQiyDefaultSCManage extends FlyQiyBaseSingleton implements FlyQiySCManage {

    // 默认的统计计算映射表
    private static final Map<String, Class<? extends FlyQiuCalculate<?>>> DEFAULT_CALCULATE_MAP = new HashMap<>();

    // 初始化默认的统计计算映射表
    static {
        // 数字计算类型
        DEFAULT_CALCULATE_MAP.put(FlyQiuAvgCalculate.CALCULATE_TYPE_AVG, FlyQiuAvgCalculate.class);
        DEFAULT_CALCULATE_MAP.put(FlyQiuMaxCalculate.CALCULATE_TYPE_MAX, FlyQiuMaxCalculate.class);
        DEFAULT_CALCULATE_MAP.put(FlyQiuMinCalculate.CALCULATE_TYPE_MIN, FlyQiuMinCalculate.class);
        DEFAULT_CALCULATE_MAP.put(FlyQiuSumCalculate.CALCULATE_TYPE_SUM, FlyQiuSumCalculate.class);
        DEFAULT_CALCULATE_MAP.put(FlyQiuCountCalculate.CALCULATE_TYPE_COUNT, FlyQiuCountCalculate.class);

        // 字符类型
        DEFAULT_CALCULATE_MAP.put(FlyQiuConcatCalculate.CALCULATE_TYPE_CONCAT, FlyQiuConcatCalculate.class);
    }

    /**
     * 获取单例实例。
     *
     * @return 单例实例
     */
    @SuppressWarnings("unused")
    public static FlyQiyDefaultSCManage getInstance() {
        return FlyQiuSingletonFactory.get(FlyQiyDefaultSCManage.class);
    }

    /**
     * 注册新的统计计算类型。
     *
     * @param calculateType  计算类型
     * @param calculateClazz 计算类
     */
    @Override
    public <T extends FlyQiuCalculate<?>> void register(String calculateType, Class<T> calculateClazz) {
        if (StringUtils.isBlank(calculateType)) {
            throw new IllegalArgumentException("calculateType cannot be blank or null");
        }
        if (calculateClazz == null) {
            throw new NullPointerException("calculateClazz cannot be null");
        }
        try {
            calculateClazz.getDeclaredConstructor();
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Class " + calculateClazz.getName() + " does not have a default constructor.", e);
        }
        DEFAULT_CALCULATE_MAP.put(calculateType, calculateClazz);
    }

    /**
     * 创建指定类型的统计计算实例。
     *
     * @param calculateType 计算类型
     * @return 统计计算实例
     */
    @Override
    public FlyQiuCalculate<?> createCalculate(String calculateType) {
        Class<? extends FlyQiuCalculate<?>> clazz = DEFAULT_CALCULATE_MAP.get(calculateType);
        return FlyQiuClassTools.createObject(clazz);
    }

    /**
     * 创建 JSON 对象类型的统计上下文。
     *
     * @param dataSource 数据源
     * @param key        键值
     * @return 统计上下文
     */
    @Override
    public FlyQiuSCContext<JSONObject> createContext(JSONArray dataSource, Object key) {
        FlyQiuDefaultSCContext<JSONObject> context = new FlyQiuDefaultSCContext<>();
        context.setScManage(this);
        context.setKey(key);
        List<JSONObject> list = dataSource.toList(JSONObject.class);
        context.setDataSourceSize(dataSource.size());
        context.setDataSource(list);
        return context;
    }

    /**
     * 创建泛型类型的统计上下文。
     *
     * @param dataSource 数据源
     * @param key        键值
     * @param <T>        数据源中的元素类型
     * @return 统计上下文
     */
    @Override
    public <T> FlyQiuSCContext<T> createContext(Collection<T> dataSource, Object key) {
        FlyQiuDefaultSCContext<T> context = new FlyQiuDefaultSCContext<>();
        context.setScManage(this);
        context.setKey(key);
        context.setDataSource(dataSource);
        context.setDataSourceSize(dataSource.size());
        return context;
    }

    /**
     * 执行统计计算。
     *
     * @param context 统计上下文
     * @param rules   统计规则列表
     * @param <T>     数据源中的元素类型
     * @return 结果 JSON 对象
     */
    @Override
    public <T> JSONObject statistical(FlyQiuSCContext<? extends T> context, List<FlyQiuPropertyStatistical<T>> rules) {
        Collection<? extends T> dataSource = context.getDataSource();

        FlyQiuCollectionTools.iteratorIndex(dataSource, (row, index) -> {
            context.setRowIndex(index);
            for (FlyQiuPropertyStatistical<T> statistical : rules) {
                context.setStatisticalInstance(statistical);
                statistical.calculate(context, row);
            }
        });

        JSONObject result = new JSONObject();
        for (FlyQiuPropertyStatistical<?> statistical : rules) {
            result.put(statistical.getFieldName(), statistical.getStatisticalValue());
            statistical.resetValue();
        }
        return result;
    }

    /**
     * 获取默认的统计计算映射表。
     *
     * @return 默认的统计计算映射表
     */
    @SuppressWarnings("unused")
    public static Map<String, Class<? extends FlyQiuCalculate<?>>> getDefaultCalculateMap() {
        return new HashMap<>(DEFAULT_CALCULATE_MAP);
    }
}
